package com.tx.listener.wslistener;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.tx.constant.RedisKey;
import com.tx.constant.WsEvent;
import com.tx.model.WsSubscribeRequest;
import com.tx.server.WebSocketListener;
import com.tx.utils.WsResultUtil;
import com.tx.wsclient.WsClient;
import com.tx.wsclient.WsClientManager;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.FullHttpRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;


/**
 * @author dengguoxing
 * @date 2019/11/07
 * description
 **/
@Service
public class MarketdataWsListener extends WebSocketListener {

    private static final String SYMBOL_KEY_PERFIX = "config:common:symbols:";

    @Autowired
    @Qualifier("mkdataRedisStringTemplate")
    private StringRedisTemplate mkdataStringTemplate;


    @Override
    public void onOpen(ChannelHandlerContext ctx, FullHttpRequest req) throws Exception {
        String id =   ctx.channel().id().asLongText();
        logger.info("ws 【{}】 open", id);

        //每个客户端都保存一个对象;String id,Set topic , private Channel channel,Date connectDate
        WsClient wsClient =new WsClient();
        wsClient.setId(id);
        wsClient.setChannel(ctx.channel());
        System.out.println(ctx.channel());
        // 一个id 一个对象，面向对象编程；管理ws链接客户端的连接。
        WsClientManager.addWsClient(id, wsClient);

    }

    @Override
    public void onMessage(ChannelHandlerContext ctx, String msg) throws Exception {
        //从哪一个客户端过来的
        String id = ctx.channel().id().asLongText();
        logger.info("ws 【{}】 msg: {}", id, msg);

       WsClient wsClient = WsClientManager.getWsClient(id);

        wsClient.setLastMsgDate(new Date());
        logger.info("received request:{}", msg);

        // 处理消息

        if(JSONUtil.isJsonObj(msg)){
            WsSubscribeRequest wsMessage = JSON.parseObject(msg,WsSubscribeRequest.class);
            System.out.println(wsMessage.getFrequency());
            System.out.println(wsMessage.getEvent());
            WsEvent wsEvent = WsEvent.fromValue(wsMessage.getEvent());
            List<String> topics = wsMessage.getTopic();
            if(wsEvent == null || topics == null || topics.size() == 0){
                return;
            }

            for(String topic :topics) {
                switch (wsEvent){
                    case SUB:
                        //订阅
                        subTopic(wsClient,topic);
                        break;
                    case UNSUB:
                        //取消订阅
                        unSubTopic(wsClient,topic);
                        break;
                    default:
                        break;
                }
            }
        }
    }


    /**    channel到生命周期末的时候调用的函数，理论上，报错关闭或者主动关闭都会经过这里
     所以在这里处理一次就可以, 取消订阅，然后删除
     **/
    @Override
    public void onClosed(ChannelHandlerContext ctx) throws Exception {
        String id = ctx.channel().id().asLongText();
        logger.info("ws 【{}】 closed", id);
        //取消订阅，然后删除
        WsClient wsClient =WsClientManager.getWsClient(id);
        if(wsClient != null){
            wsClient.unSubAllTopic();
            WsClientManager.delWsClient(id);
        }

    }







    @Override
    public void onFailure(ChannelHandlerContext ctx, Throwable t) throws Exception {
        String id = ctx.channel().id().asLongText();
        logger.info("ws 【{}】 failure t.msg: {}, t.stack: {}", id, t.getMessage(), t.getStackTrace());
    }

    @Override
    public void onHeartBroken(ChannelHandlerContext ctx) throws Exception {
        String id = ctx.channel().id().asLongText();
        logger.info("ws 【{}】 heart broken", id);
        // 取消订阅，然后删除
        WsClient wsClient = WsClientManager.getWsClient(id);
        if (wsClient != null) {
            wsClient.send(WsEvent.SYSTEM.getValue(), WsEvent.SYSTEM.getValue(), WsResultUtil.error("30秒没消息，断开连接！"));
            wsClient.close();
        }

    }

    /**
    * 订阅主题
    *
    * */

    private  void subTopic(WsClient wsClient,String topic){
        //判断主题
        boolean isPass = verifiTopic(topic);
        if (isPass) {
            wsClient.subTopic(topic);
            wsClient.send(WsEvent.SUBED.getValue(), topic, WsResultUtil.success("订阅成功！"));;

        } else{
            wsClient.send(WsEvent.SUBED.getValue(),topic,WsResultUtil.error("订阅失败，请检测主题是否正确！"));
        }
    }

    /**
     * 取消订阅主题
     * @param wsClient
     * @param topic
     */
    private  void unSubTopic ( WsClient wsClient,String topic){

        // 判断主题
        boolean isPass = verifiTopic(topic);
        if (isPass) {
            wsClient.unSubTopic(topic);
            wsClient.send(WsEvent.UNSUBED.getValue(), topic, WsResultUtil.success("取消订阅成功！"));
        } else {
            wsClient.send(WsEvent.UNSUBED.getValue(), topic, WsResultUtil.error("取消订阅失败，请检测主题是否正确！"));
        }


    }



    /**
     * 校验订阅的主题
     //1. 我们的key都是小写的 。
     // 2. config:common:symbols:binance:marginc:ada_btc 有币，但是没有book，提示成功但是没有book
     // 3 没有找到symbol则提示失败
     * @param topic
     * @return
     */
    private boolean verifiTopic(String topic) {
        String subtopic = topic.toLowerCase();
        if (StrUtil.isBlank(subtopic) ) {
            return false;
        }

        //当前只支持ticker与book的订阅
        if(!topic.startsWith(RedisKey.BOOK)&&!topic.startsWith(RedisKey.TICKER))
        {
            return  false;
        }

        //把前面的book去掉 book:binance:spot:ada_bnb   topic.substring(topic.indexOf(":") + 1)
        String key = SYMBOL_KEY_PERFIX + topic.substring(topic.indexOf(":") + 1);

        if  (mkdataStringTemplate.opsForValue().get(key) !=null) {
            return true;
        }

        return false;
    }








}
